﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;

namespace Booky.Common
{
    /// <summary>
    /// Encryption for serializable objects
    /// </summary>
    public class Encryption
    {
        private readonly string encryptionKey = "!bookyurl!";
        private readonly byte[] salt;

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Encryption"/> class.
        /// </summary>
        public Encryption()
        {
            this.salt = Encoding.ASCII.GetBytes(encryptionKey);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Encryption"/> class.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        public Encryption(string key)
        {
            this.encryptionKey = key;
            this.salt = Encoding.ASCII.GetBytes(encryptionKey);
        }

        #endregion

        #region Encrypt

        

        /// <summary>
        ///   Encrypts any string using the Rijndael algorithm.
        /// </summary>
        /// <param name = "inputText">The string to encrypt.</param>
        /// <returns>
        /// A Base64 encrypted string.
        /// </returns>
        public string Encrypt(string inputText)
        {
            var rijndaelCipher = new RijndaelManaged();
            byte[] plainText = Encoding.Unicode.GetBytes(inputText);
            var secretKey = new Rfc2898DeriveBytes(encryptionKey, salt);

            using (var encryptor = rijndaelCipher.CreateEncryptor(rgbKey: secretKey.GetBytes(32), rgbIV: secretKey.GetBytes(16)))
            {
                using (var memoryStream = new MemoryStream())
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainText, 0, plainText.Length);
                        cryptoStream.FlushFinalBlock();
                        return Convert.ToBase64String(memoryStream.ToArray());
                    }
                }
            }
        }

        #endregion

        #region Decrypt

        /// <summary>
        ///   Decrypts a previously encrypted string.
        /// </summary>
        /// <param name = "inputText">The encrypted string to decrypt.</param>
        /// <returns>A decrypted string.</returns>
        public string Decrypt(string inputText)
        {
            var rijndaelCipher = new RijndaelManaged();
            var encryptedData = Convert.FromBase64String(inputText);
            var secretKey = new Rfc2898DeriveBytes(encryptionKey, salt);

            using (var decryptor = rijndaelCipher.CreateDecryptor(rgbKey: secretKey.GetBytes(32), rgbIV: secretKey.GetBytes(16)))
            {
                using (var memoryStream = new MemoryStream(encryptedData))
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        var plainText = new byte[encryptedData.Length];
                        var decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
                        return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
                    }
                }
            }
        }

        #endregion

       
    }
}
